package com.sz.biz.app.web.security;

import com.sz.common.base.logger.Logger;

import com.sz.common.core.service.Principal;
import com.sz.common.core.service.PrincipalUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;

/**
 * Function: KickoutSessionControlFilter <br>
 * Author: Charles <br>
 * Date: 2016-12-21 16:27:00
 */
@Service
public class KickoutSessionControlFilter extends AccessControlFilter {

    @Autowired
    private OnlineSessionManager onlineSessionManager;

    Logger logger = Logger.getLogger(this.getClass());

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //如果被踢出了，直接退出，重定向到踢出后的地址
        if (!checkConcurrenceLogin()) {
            //会话被踢出了
            try {
                Subject subject = SecurityUtils.getSubject();
                logger.info(String.format("user [%s] with sessionId [%s] is kicked out",
                        subject.getPrincipal(),
                        subject.getSession().getId()));
                subject.logout();
            } catch (Exception e) { //ignore
                logger.warn("exception occurred when kick out user", e);
            }
            saveRequest(request);
            ((HttpServletResponse) response).sendError(401, "You are kicked out");
            response.flushBuffer();
            return false;
        }
        return true;
    }

    /**
     * 检查是否存在同一个账户多点登陆(踢出先登陆者)
     */
    private boolean checkConcurrenceLogin() {
        Principal principal = PrincipalUtils.tryToGetPrincipal();
        if (principal == null || principal.isRoot()) { // do nothing for root
            return true;
        }

        Serializable sessionId = SecurityUtils.getSubject().getSession().getId();

        String username = principal.getAccountName();
        String lastSessionId = (String) onlineSessionManager.getSessionId(username);
        return !(lastSessionId != null && !lastSessionId.equals(sessionId));
    }
}
